package com.investment.advisor.utils;

import com.investment.advisor.entity.*;
import com.investment.advisor.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Component
public class DataInitializer implements CommandLineRunner {

    private final FundRepository fundRepository;
    private final TagRepository tagRepository;
    private final StrategyRepository strategyRepository;
    private final FactorRepository factorRepository;
    private final StrategyFactorRepository strategyFactorRepository;
    private final PortfolioRepository portfolioRepository;
    private final PortfolioFundRepository portfolioFundRepository;
    private final TradeRepository tradeRepository;
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public DataInitializer(FundRepository fundRepository, 
                          TagRepository tagRepository,
                          StrategyRepository strategyRepository,
                          FactorRepository factorRepository,
                          StrategyFactorRepository strategyFactorRepository,
                          PortfolioRepository portfolioRepository,
                          PortfolioFundRepository portfolioFundRepository,
                          TradeRepository tradeRepository,
                          UserRepository userRepository,
                          BCryptPasswordEncoder passwordEncoder) {
        this.fundRepository = fundRepository;
        this.tagRepository = tagRepository;
        this.strategyRepository = strategyRepository;
        this.factorRepository = factorRepository;
        this.strategyFactorRepository = strategyFactorRepository;
        this.portfolioRepository = portfolioRepository;
        this.portfolioFundRepository = portfolioFundRepository;
        this.tradeRepository = tradeRepository;
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    @Transactional
    public void run(String... args) {
        // 如果数据库中没有数据，则初始化数据
        if (fundRepository.count() == 0 && tagRepository.count() == 0) {
            initializeUsers();
            initializeTags();
            initializeFunds();
            initializeFactors();
            initializeStrategies();
            initializePortfolios();
            initializeTrades();
        }
    }

    private void initializeUsers() {
        if (userRepository.count() == 0) {
            User admin = new User();
            admin.setUsername("admin");
            admin.setPassword(passwordEncoder.encode("admin123"));
            admin.setEmail("admin@example.com");
            admin.setRole("ADMIN");
            admin.setCreateTime(LocalDateTime.now());
            admin.setUpdateTime(LocalDateTime.now());
            userRepository.save(admin);
        }
    }

    private void initializeTags() {
        // 创建标签
        Tag[] tags = {
            createTag("低风险", "风险类别", "波动较小，适合保守型投资者"),
            createTag("中风险", "风险类别", "波动适中，适合稳健型投资者"),
            createTag("高风险", "风险类别", "波动较大，适合激进型投资者"),
            createTag("价值投资", "投资风格", "关注被低估的股票"),
            createTag("成长投资", "投资风格", "关注高成长性的股票"),
            createTag("指数型", "基金类型", "跟踪特定指数的表现"),
            createTag("主动管理", "管理方式", "基金经理主动选股"),
            createTag("被动管理", "管理方式", "跟踪指数，较少主动干预"),
            createTag("大盘", "市场分类", "关注大市值公司"),
            createTag("中小盘", "市场分类", "关注中小市值公司")
        };

        // 保存所有标签
        tagRepository.saveAll(Arrays.asList(tags));
    }

    private Tag createTag(String name, String category, String description) {
        Tag tag = new Tag();
        tag.setName(name);
        tag.setCategory(category);
        tag.setDescription(description);
        return tag;
    }

    private void initializeFunds() {
        // 获取已创建的标签
        Optional<Tag> lowRisk = tagRepository.findByName("低风险");
        Optional<Tag> mediumRisk = tagRepository.findByName("中风险");
        Optional<Tag> highRisk = tagRepository.findByName("高风险");
        Optional<Tag> valueInvest = tagRepository.findByName("价值投资");
        Optional<Tag> growthInvest = tagRepository.findByName("成长投资");
        Optional<Tag> indexFund = tagRepository.findByName("指数型");
        Optional<Tag> activeManage = tagRepository.findByName("主动管理");
        Optional<Tag> passiveManage = tagRepository.findByName("被动管理");
        Optional<Tag> largeCap = tagRepository.findByName("大盘");
        Optional<Tag> smallMidCap = tagRepository.findByName("中小盘");

        // 创建示例基金
        Fund[] funds = {
            createFund(
                "000001", "示例平衡型基金", "混合型", new BigDecimal("1.2345"),
                new BigDecimal("0.0123"), new BigDecimal("0.0234"), new BigDecimal("0.0345"), new BigDecimal("0.1234"),
                new BigDecimal("10.5"), "张三", "示例基金公司", "这是一个平衡型基金，适合稳健型投资者。", 4,
                getTagSet(mediumRisk, valueInvest, activeManage)
            ),
            createFund(
                "000002", "示例成长型基金", "股票型", new BigDecimal("1.5678"),
                new BigDecimal("0.0234"), new BigDecimal("0.0345"), new BigDecimal("0.0456"), new BigDecimal("0.2345"),
                new BigDecimal("15.2"), "李四", "示例基金公司", "这是一个成长型基金，专注于高增长企业。", 5,
                getTagSet(highRisk, growthInvest, activeManage, smallMidCap)
            ),
            createFund(
                "000003", "示例指数型基金", "指数型", new BigDecimal("1.0123"),
                new BigDecimal("0.0111"), new BigDecimal("0.0222"), new BigDecimal("0.0333"), new BigDecimal("0.1111"),
                new BigDecimal("25.8"), "王五", "示例基金公司", "这是一个指数型基金，跟踪特定市场指数。", 3,
                getTagSet(mediumRisk, passiveManage, indexFund, largeCap)
            ),
            createFund(
                "000004", "示例债券型基金", "债券型", new BigDecimal("1.0456"),
                new BigDecimal("0.0022"), new BigDecimal("0.0033"), new BigDecimal("0.0055"), new BigDecimal("0.0456"),
                new BigDecimal("8.6"), "赵六", "示例基金公司", "这是一个债券型基金，投资各类债券。", 3,
                getTagSet(lowRisk, valueInvest)
            ),
            createFund(
                "000005", "示例科技行业基金", "股票型", new BigDecimal("1.8765"),
                new BigDecimal("0.0345"), new BigDecimal("0.0567"), new BigDecimal("0.0789"), new BigDecimal("0.3456"),
                new BigDecimal("12.3"), "钱七", "示例基金公司", "这是一个科技行业基金，专注于科技企业投资。", 4,
                getTagSet(highRisk, growthInvest, activeManage)
            )
        };

        // 保存所有基金
        fundRepository.saveAll(Arrays.asList(funds));
    }

    private Fund createFund(String code, String name, String type, BigDecimal nav,
                           BigDecimal dailyReturn, BigDecimal weeklyReturn, BigDecimal monthlyReturn, BigDecimal yearlyReturn,
                           BigDecimal size, String manager, String company, String description, Integer rating,
                           Set<Tag> tags) {
        Fund fund = new Fund();
        fund.setCode(code);
        fund.setName(name);
        fund.setType(type);
        fund.setNav(nav);
        fund.setDailyReturn(dailyReturn);
        fund.setWeeklyReturn(weeklyReturn);
        fund.setMonthlyReturn(monthlyReturn);
        fund.setYearlyReturn(yearlyReturn);
        fund.setSize(size);
        fund.setManager(manager);
        fund.setCompany(company);
        fund.setDescription(description);
        fund.setRating(rating);
        fund.setTags(tags);
        return fund;
    }

    private Set<Tag> getTagSet(Optional<Tag>... tags) {
        Set<Tag> tagSet = new HashSet<>();
        for (Optional<Tag> tag : tags) {
            tag.ifPresent(tagSet::add);
        }
        return tagSet;
    }
    
    private void initializeFactors() {
        // 创建示例因子
        Factor[] factors = {
            createFactor("市值因子", "基本面", "反映公司市值大小", "Market Cap = 股价 * 总股本"),
            createFactor("PE因子", "估值", "反映公司估值水平", "PE = 股价 / 每股收益"),
            createFactor("动量因子", "技术", "反映股价趋势", "过去12个月收益率")
        };
        
        // 保存所有因子
        factorRepository.saveAll(Arrays.asList(factors));
    }
    
    private Factor createFactor(String name, String category, String description, String formula) {
        Factor factor = new Factor();
        factor.setName(name);
        factor.setCategory(category);
        factor.setDescription(description);
        factor.setFormula(formula);
        return factor;
    }
    
    private void initializeStrategies() {
        // 创建示例策略
        Strategy strategy1 = createStrategy("稳健增长策略", "平衡风险和收益，追求长期稳健增长", "管理员");
        Strategy strategy2 = createStrategy("高增长策略", "追求高收益，接受较高风险", "管理员");
        Strategy strategy3 = createStrategy("低风险策略", "追求稳定收益，控制风险", "管理员");
        
        strategyRepository.save(strategy1);
        strategyRepository.save(strategy2);
        strategyRepository.save(strategy3);
        
        // 获取已创建的因子
        List<Factor> factors = factorRepository.findAll();
        if (factors.size() >= 3) {
            // 为策略添加因子和权重
            StrategyFactor sf1 = new StrategyFactor();
            sf1.setStrategy(strategy1);
            sf1.setFactor(factors.get(0));
            sf1.setWeight(new BigDecimal("0.4"));
            
            StrategyFactor sf2 = new StrategyFactor();
            sf2.setStrategy(strategy1);
            sf2.setFactor(factors.get(1));
            sf2.setWeight(new BigDecimal("0.6"));
            
            StrategyFactor sf3 = new StrategyFactor();
            sf3.setStrategy(strategy2);
            sf3.setFactor(factors.get(2));
            sf3.setWeight(new BigDecimal("1.0"));
            
            StrategyFactor sf4 = new StrategyFactor();
            sf4.setStrategy(strategy3);
            sf4.setFactor(factors.get(0));
            sf4.setWeight(new BigDecimal("0.3"));
            
            StrategyFactor sf5 = new StrategyFactor();
            sf5.setStrategy(strategy3);
            sf5.setFactor(factors.get(1));
            sf5.setWeight(new BigDecimal("0.7"));
            
            strategyFactorRepository.saveAll(Arrays.asList(sf1, sf2, sf3, sf4, sf5));
        }
    }
    
    private Strategy createStrategy(String name, String description, String creator) {
        Strategy strategy = new Strategy();
        strategy.setName(name);
        strategy.setDescription(description);
        strategy.setCreator(creator);
        strategy.setCreateTime(LocalDateTime.now());
        return strategy;
    }
    
    private void initializePortfolios() {
        // 获取已创建的策略和基金
        List<Strategy> strategies = strategyRepository.findAll();
        List<Fund> funds = fundRepository.findAll();
        
        if (!strategies.isEmpty() && !funds.isEmpty()) {
            // 创建示例组合
            Portfolio portfolio1 = createPortfolio("示例平衡组合", strategies.get(0), "管理员");
            Portfolio portfolio2 = createPortfolio("示例进取组合", strategies.get(1), "管理员");
            Portfolio portfolio3 = createPortfolio("示例保守组合", strategies.get(2), "管理员");
            
            portfolioRepository.saveAll(Arrays.asList(portfolio1, portfolio2, portfolio3));
            
            // 为组合添加基金和权重
            if (funds.size() >= 3) {
                PortfolioFund pf1 = new PortfolioFund();
                pf1.setPortfolio(portfolio1);
                pf1.setFund(funds.get(0));
                pf1.setWeight(new BigDecimal("0.6"));
                
                PortfolioFund pf2 = new PortfolioFund();
                pf2.setPortfolio(portfolio1);
                pf2.setFund(funds.get(1));
                pf2.setWeight(new BigDecimal("0.4"));
                
                PortfolioFund pf3 = new PortfolioFund();
                pf3.setPortfolio(portfolio2);
                pf3.setFund(funds.get(2));
                pf3.setWeight(new BigDecimal("1.0"));
                
                PortfolioFund pf4 = new PortfolioFund();
                pf4.setPortfolio(portfolio3);
                pf4.setFund(funds.get(3));
                pf4.setWeight(new BigDecimal("1.0"));
                
                portfolioFundRepository.saveAll(Arrays.asList(pf1, pf2, pf3, pf4));
            }
        }
    }
    
    private Portfolio createPortfolio(String name, Strategy strategy, String creator) {
        Portfolio portfolio = new Portfolio();
        portfolio.setName(name);
        portfolio.setStrategy(strategy);
        portfolio.setCreator(creator);
        portfolio.setCreateTime(LocalDateTime.now());
        return portfolio;
    }
    
    private void initializeTrades() {
        // 获取已创建的组合和基金
        List<Portfolio> portfolios = portfolioRepository.findAll();
        List<Fund> funds = fundRepository.findAll();
        
        if (!portfolios.isEmpty() && !funds.isEmpty()) {
            // 创建示例交易
            Trade trade1 = createTrade(portfolios.get(0), funds.get(0), "买入", 
                                      new BigDecimal("10000"), funds.get(0).getNav(), 
                                      LocalDate.now().minusDays(5), "已完成", "管理员");
            
            Trade trade2 = createTrade(portfolios.get(0), funds.get(1), "买入", 
                                      new BigDecimal("15000"), funds.get(1).getNav(), 
                                      LocalDate.now().minusDays(3), "已完成", "管理员");
            
            Trade trade3 = createTrade(portfolios.get(1), funds.get(2), "买入", 
                                      new BigDecimal("20000"), funds.get(2).getNav(), 
                                      LocalDate.now().minusDays(1), "已完成", "管理员");
            
            tradeRepository.saveAll(Arrays.asList(trade1, trade2, trade3));
        }
    }
    
    private Trade createTrade(Portfolio portfolio, Fund fund, String action, 
                             BigDecimal amount, BigDecimal price, 
                             LocalDate date, String status, String creator) {
        Trade trade = new Trade();
        trade.setPortfolio(portfolio);
        trade.setFund(fund);
        trade.setAction(action);
        trade.setAmount(amount);
        trade.setPrice(price);
        trade.setTradeDate(date);
        trade.setStatus(status);
        trade.setCreator(creator);
        return trade;
    }
} 